﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Web.UI.WebControls;
using System.Reflection;
using System.Web;
using System.Web.UI;
using System.Linq.Expressions;
using System.Linq.Dynamic;

namespace Catalyst.Web.DynamicData
{
    /// <summary>
    /// The DynamicExpressionParameterBase extends System.Web.UI.WebControls.Parameter to provide the ability to generate complex
    /// LambdaExpressions that provided filtering capability beyond simple equality.
    /// </summary>
    public abstract class DynamicExpressionParameterBase : System.Web.UI.WebControls.Parameter, IDynamicExpressionParameter
    {
        /// <summary>
        /// The abstract method responsible for building a LambdaExpression to be evaluated against the target object.
        /// </summary>
        /// <param name="itType">The type of object the LambdaExpression is evaluated against.</param>
        /// <returns>The LambdaExpression.</returns>
        public abstract LambdaExpression GetLambdaExpression(Type itType);

        /// <summary>
        /// The defafult implementation of AppendQuery is to call the Queryable.Where extension method.  This appends the
        /// LambdaExpression returned by GetLambdaExpression to the IQueryable provided.
        /// </summary>
        /// <param name="query">The Query to append the LambdaExpression with.</param>
        /// <returns>The combined IQueryable of query and GetLambdaExpression.</returns>
        public virtual IQueryable AppendQuery(IQueryable query)
        {
            Expression exp = GetLambdaExpression(query.ElementType);
            if (exp == null)
                return query;

            return query.Provider.CreateQuery
                (
                     Expression.Call
                     (
                        typeof(Queryable),
                        "Where",
                        new Type[] { query.ElementType },
                        query.Expression,
                        Expression.Quote(exp)
                     )
                 );
        }

        internal static object GetValue(object value, string defaultValue, TypeCode type, bool convertEmptyStringToNull, bool ignoreNullableTypeChanges)
        {
            if (type == TypeCode.DBNull)
                return DBNull.Value;
            
            value = HandleNullValue(value, defaultValue, convertEmptyStringToNull);
            if (value == null)
                return null;
            
            if ((type == TypeCode.Object) || (type == TypeCode.Empty))
                return value;
            
            if (ignoreNullableTypeChanges && IsNullableType(value.GetType()))
                return value;
            
            return (value = Convert.ChangeType(value, type, CultureInfo.CurrentCulture));
        }

        private static object HandleNullValue(object value, string defaultValue, bool convertEmptyStringToNull)
        {
            if (convertEmptyStringToNull)
            {
                string str = value as string;
                if ((str != null) && (str.Length == 0))
                    value = null;
            }

            if (value == null)
            {
                if (convertEmptyStringToNull && string.IsNullOrEmpty(defaultValue))
                    defaultValue = null;
                
                if (defaultValue == null)
                    return null;
                
                value = defaultValue;
            }
            return value;
        }

        private static bool IsNullableType(Type type)
        {
            return (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(Nullable<>)));
        }
    }
}
